/* Copyright (c) 2021, National University of Defense Technology. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "multivector.h"

namespace YHAMG
{

MultiVector::MultiVector()
	: ref(0),
	num_vectors(0),
	size(0),
	values(0)
{
}

MultiVector::MultiVector(int _m, int _n, double* _values, int _ref)
	: ref(_ref),
	num_vectors(_m),
	size(_n),
	values(_values)
{
}

MultiVector::MultiVector(const MultiVector& X)
	: ref(0),
	num_vectors(X.num_vectors),
	size(X.size),
	values(new double[X.size * X.num_vectors])
{
	double* Xv = X.values;
	for (int j = 0; j < num_vectors; ++j)
		for (int i = 0; i < size; ++i)
			values[i + j * size] = Xv[i + j * size];
}

MultiVector::MultiVector(MultiVector&& X)
	: ref(X.ref),
	num_vectors(X.num_vectors),
	size(X.size),
	values(X.values)
{
	X.ref = 1;
}

MultiVector::~MultiVector()
{
	if (!ref && values) delete[] values;
}

MultiVector& MultiVector::operator=(const MultiVector& X)
{
	if (!ref && values) delete[] values;
	ref = 0;
	num_vectors = X.num_vectors;
	size = X.size;
	values = new double[X.size * X.num_vectors];

	double* Xv = X.values;
	for (int j = 0; j < num_vectors; ++j)
		for (int i = 0; i < size; ++i)
			values[i + j * size] = Xv[i + j * size];

	return *this;
}

MultiVector& MultiVector::operator=(MultiVector&& X)
{
	if (!ref && values) delete[] values;
	ref = X.ref;
	num_vectors = X.num_vectors;
	size = X.size;
	values = X.values;

	X.ref = 1;

	return *this;
}

void MultiVector::Free()
{
	if (!ref && values) delete[] values;
	ref = 0;
	num_vectors = 0;
	size = 0;
	values = 0;
}

void MultiVector::Allocate(int m, int n)
{
	if (!ref && values) delete[] values;
	ref = 0;
	num_vectors = m;
	size = n;
	values = new double[n * m];
}

void MultiVector::Reference(const MultiVector& X)
{
	if (!ref && values) delete[] values;
	ref = 1;
	num_vectors = X.num_vectors;
	size = X.size;
	values = X.values;
}

const Vector MultiVector::operator()(int j) const
{
	return Vector(size, values + j * size, 1);
}

}